package org.ddd.specification.jpa.conversion;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.ddd.specification.Specification;
import org.ddd.specification.jpa.JpaSpecification;

public class ConversionInvokingJpaSpecification<X> extends JpaSpecification<X> {
    private Object conversionHandler;
    private Method conversionMethod;

    public ConversionInvokingJpaSpecification(Specification<X> specification, Object conversionHandler, Method conversionMethod) {
        super(specification);
        this.conversionHandler = conversionHandler;
        this.conversionMethod = conversionMethod;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Predicate toPredicate(Root<X> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        try {
            // TODO: Allow more flexibility in the order of arguments
            Object predicate = conversionMethod.invoke(conversionHandler, getWrappedSpecification(), root, criteriaQuery, criteriaBuilder);
            return (Predicate) predicate;
        } catch (IllegalArgumentException e) {
            throw new IllegalStateException(e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(e);
        } catch (InvocationTargetException e) {
            throw new IllegalStateException(e);
        }
    }

}
